package curves.math;

import java.util.ArrayList;
import java.util.List;
import curves.CurveAlgorithm;
import curves.Point;
import curves.sys.MPoint;

public class DeCasteljanCurveAlgorithm implements CurveAlgorithm {

    public List<Point> calculatePoints(List<Point> initialPoints, boolean open, int steps, int start, int end) {

        ArrayList<Point> rpoints = new ArrayList<Point>();

        rpoints.clear();
        if (initialPoints.size() != 4) {
            return new ArrayList<Point>();
        }

        List<Point> points = new ArrayList<Point>();
        List<Point> temp = new ArrayList<Point>();
        List<Point> ptemp = new ArrayList<Point>();

        rpoints.addAll(initialPoints);

        for (int k = 0; k < steps; k++) {
            points.clear();
            for (int i = 0; i + 3 < rpoints.size(); i += 3) {
                temp.clear();
                temp.add(rpoints.get(i).weight());
                temp.add(rpoints.get(i + 1).weight());
                temp.add(rpoints.get(i + 2).weight());
                temp.add(rpoints.get(i + 3).weight());
                ptemp.clear();
                ptemp.addAll(recurCastel(temp));
                if (i != 0) {
                    ptemp.remove(0);
                }

                for (Point pp : ptemp) {
                    points.add(pp.unweight());
                }
            }
            rpoints.clear();
            rpoints.addAll(points);
        }

        return rpoints;
    }

    protected List<Point> deCastel(List<Point> point) {
        /**
         *  Input: array P[0:n] of n+1 points and real number u in [0,1] 
        Output: point on curve, C(u)
        Working: point array Q[0:n]

        for i := 0 to n do
        Q[i] := P[i]; // save input
        for k := 1 to n do
        for i := 0 to n - k do
        Q[i] := (1 - u)Q[i] + u Q[i + 1];
        return Q[0];
         */
        double u = 0.5;
        List<Point> myPoints = new ArrayList<Point>();
        myPoints.addAll(point);
        for (int k = 1; k < point.size(); k++) {
            for (int i = 0; i < point.size() - k; i++) {
                myPoints.add(i, myPoints.get(i).part(myPoints.get(i + 1), u));
            }
        }

        return myPoints;
    }

    protected List<Point> recurCastel(List<Point> point) {

        if (point.size() == 1) {
            return point;
        }

        List<Point> pNew = new ArrayList<Point>();

        for (int i = 0; i + 1 < point.size(); i++) {
            double x = (point.get(i).getX() + point.get(i + 1).getX()) * 0.5;
            double y = (point.get(i).getY() + point.get(i + 1).getY()) * 0.5;
            double w = (point.get(i).getWeight() + point.get(i + 1).getWeight()) * 0.5;

            pNew.add(new MPoint(x, y, w));
        }

        List<Point> newz = new ArrayList<Point>();
        newz.addAll(recurCastel(pNew));
        newz.add(0, point.get(0));
        newz.add(point.get(point.size() - 1));
        return newz;
    }

    @Override
    public String toString() {
        return "de Casteljan";
    }
}
